//
//  MIPRenderer.m
//  V3d_Cocoa
//
//  Created by Y my on 11-4-23.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "MIPRenderer.h"


#define MAX2(a, b) ( (a) >= (b) ? (a) : (b) )
#define MAX4(a, b, c, d) ( MAX2( MAX2(a, b), MAX2(c, d) ) )


@interface MIPRenderer ()

// templates ////////////////////////////
- (void)calculateTemplates; // 将一个Cell的六个面依次投影，并返回投影后z值最大的点的索引
- (void)rasterizeFaceWithIndex_1_2:(char)index toTemplateList:(char)listIndex;
- (void)rasterizeFaceWithIndex_3_4:(char)index toTemplateList:(char)listIndex;
- (void)rasterizeFaceWithIndex_5_6:(char)index toTemplateList:(char)listIndex;
- (void)generateVoxelTemplate:(Point3D*)v toTemplateList:(char)listIndex;

// projection array ////////////////////
- (void)calculateProjectionArrays;

// project every cell //////////////////
- (void)projectEveryCells;
- (void)projectCellWithV1X:(unsigned short)v1x
					   V1Y:(unsigned short)v1y
					   V1Z:(unsigned short)v1z
				   andCmax:(unsigned char)Cmax;

- (RGB)trillearInterpolationInCell_V1X:(unsigned short)v1x
											 V1Y:(unsigned short)v1y
											 V1Z:(unsigned short)v1z
									PointWeightU:(float)u
											   V:(float)v
											   W:(float)w;

// other ///////////////////////////////
- (void)clean;
- (void)addTemplate:(Template*)template toList:(char)listIndex; // 添加一个模版到链表表首
- (Template*)findTemplateFromList:(char)listIndex WithX:(short)x Y:(short)y;
- (void)delTemplateList:(char)listIndex;  // 删除一条链表
- (unsigned char)intensity:(RGB)color;
- (RGB)getColorAtX:(unsigned short)x Y:(unsigned short)y Z:(unsigned short)z;
- (RGB)colorAverageWithColor1:(RGB)color1 Color2:(RGB)color2;
- (void)remapColor:(RGB*)color;

@end


@implementation MIPRenderer

- (id)initWithViewWidth:(unsigned short)width
				 Height:(unsigned short)height
		BackgroundColor:(RGB)color
{
	self = [super initWithViewWidth:width Height:height BackgroundColor:color];
	if (self)
	{
		sortedBucketInfo = NULL;
		sortedCellCoord = NULL;
		totalCellCount = 0;
		totalBucketCount = 0;
		XimgFromX3D = NULL;
		XimgFromY3D = NULL;
		XimgFromZ3D = NULL;
		YimgFromX3D = NULL;
		YimgFromY3D = NULL;
		YimgFromZ3D = NULL;
		memset(templates, 0, sizeof(templates));
	}
	return self;
}

- (void)dealloc
{
	[self clean];
	
	[super dealloc];
}

// inhert from super class /////////////////
- (CGImageRef)proceed
{
#ifndef _TEST_
	if (rawData == NULL)
	{
		return NULL;
	}
#endif
	MIPData* mipData = (MIPData*)volData;
	if (viewImage == NULL)  // 还没有进行数据预处理
	{
		[mipData proceed];
		viewImage = malloc(sizeof(RGB) * viewHeight * viewWidth);
	}
	memset(viewImage, 0, sizeof(RGB) * viewHeight * viewWidth);
		
	if (hasRotated)  // 平移操作时不需要重新计算模版
	{
		[mipData getDataResultByRotationMatrix:matRotate
						  out_TotalBucketCount:&totalBucketCount
						  out_SortedBucketInfo:&sortedBucketInfo
							out_TotalCellCount:&totalCellCount
						   out_SortedCellCoord:&sortedCellCoord ];
		[self calImageSize];
		[self calculateTemplates];
		[self calculateProjectionArrays];
		[self projectEveryCells];
	}
	
#ifdef _TEST_
	for (unsigned int i = 0; i < imageHeight; i++)
	{
		for (unsigned int j = 0; j < imageWidth; j++)
		{
			printf("%d\t", entireImage[i * imageWidth + j].r);
		}
		printf("\n");
	}
#endif
	
	if (hasRotated || hasMoved)
	{
		[self clip];
		hasRotated = NO;
		hasMoved = NO;
	}

	// 构建CGImage
	
	NSLog(@"Begin create CGImageRef");
	unsigned int count = viewWidth * viewHeight;
	if (levelLowBound != 0 || levelUpBound != 255)
	{
		for (unsigned int i = 0; i < count; i++)
		{
			[self remapColor:&viewImage[i]];
		}
	}
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
	CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, (unsigned char*)viewImage, count*4, NULL);
	
	CGImageRef pixmap = CGImageCreate(viewWidth, viewHeight, 8, 32, viewWidth*4,
									  colorSpace, kCGImageAlphaNoneSkipLast, provider,
									  NULL, YES,  kCGRenderingIntentDefault);
	
	CGColorSpaceRelease(colorSpace);
	CGDataProviderRelease(provider);
	NSLog(@"End create CGImageRef");
	
	return pixmap;

}

- (void)setVolData:(MIPData*)vData
{
	[self clean];
	[super setVolData:vData];
}

// private - templates ////////////////////////////
- (void)calculateTemplates
{
	NSLog(@"Begin calculateTemplates");
	
	unsigned char listIndex = 0;
	for (char subY = 0; subY < 4; subY++)
	{
		for (char subX = 0; subX < 4; subX++)
		{
			matTemplate = [[Matrix4 alloc] initWithMatrix4:matRotate];
			matTemplate._30 = 0.25 * subX;
			matTemplate._31 = 0.25 * subY;
			[self rasterizeFaceWithIndex_1_2:1 toTemplateList:listIndex];
			[self rasterizeFaceWithIndex_1_2:2 toTemplateList:listIndex];
			[self rasterizeFaceWithIndex_3_4:3 toTemplateList:listIndex];
			[self rasterizeFaceWithIndex_3_4:4 toTemplateList:listIndex];
			[self rasterizeFaceWithIndex_5_6:5 toTemplateList:listIndex];
			[self rasterizeFaceWithIndex_5_6:6 toTemplateList:listIndex];
			[matTemplate release];
			
			listIndex++;
		}
	}
	
	
	NSLog(@"End calculateTemplates");
}

- (void)rasterizeFaceWithIndex_1_2:(char)index toTemplateList:(char)listIndex
{
	char x, y, z;
	z = (index == 1) ? 0 : pixelPerEdge-1;
	
	Point3D* point = [[Point3D alloc] init];
	for (x = 0; x < pixelPerEdge; x++)
	{
		for (y = 0; y < pixelPerEdge; y++)
		{
			point.x = x;
			point.y = y;
			point.z = z;
			
			[self generateVoxelTemplate:point toTemplateList:listIndex];
		}
	}
	
	[point release];
}

- (void)rasterizeFaceWithIndex_3_4:(char)index toTemplateList:(char)listIndex
{
	char x, y, z;
	y = (index == 3) ? 0 : pixelPerEdge-1;
	
	Point3D* point = [[Point3D alloc] init];
	for (x = 0; x < pixelPerEdge; x++)
	{
		for (z = 0; z < pixelPerEdge; z++)
		{
			point.x = x;
			point.y = y;
			point.z = z;
			
			[self generateVoxelTemplate:point toTemplateList:listIndex];
		}
	}
	
	[point release];
}

- (void)rasterizeFaceWithIndex_5_6:(char)index toTemplateList:(char)listIndex
{
	char x, y, z;
	x = (index == 5) ? 0 : pixelPerEdge-1;
	
	Point3D* point = [[Point3D alloc] init];
	for (z = 0; z < pixelPerEdge; z++)
	{
		for (y = 0; y < pixelPerEdge; y++)
		{
			point.x = x;
			point.y = y;
			point.z = z;
			
			[self generateVoxelTemplate:point toTemplateList:listIndex];
		}
	}
	
	[point release];
}

- (void)generateVoxelTemplate:(Point3D*)v toTemplateList:(char)listIndex
{
	float rayX = v.x / (pixelPerEdge-1);
	float rayY = v.y / (pixelPerEdge-1);
	float rayZ = v.z / (pixelPerEdge-1);
	
	[v multiple:matTemplate];
	[v normalize];
	
	char pixelX = (char) floor(v.x);
	char pixelY = (char) floor(v.y);
	
	Template* pt = [self findTemplateFromList:listIndex WithX:pixelX Y:pixelY];
	
	if (pt)
	{
		pt->rayX2 = rayX;
		pt->rayY2 = rayY;
		pt->rayZ2 = rayZ;
	}
	else
	{
		pt = (Template*) malloc(sizeof(Template));
		pt->rayX1 = rayX;
		pt->rayY1 = rayY;
		pt->rayZ1 = rayZ;
		pt->x_offset = pixelX;
		pt->y_offset = pixelY;
		pt->next = NULL;
		
		[self addTemplate:pt toList:listIndex];
	}

}

// private - projection array ////////////////////
- (void)calculateProjectionArrays
{
	NSLog(@"Begin calculate projection arrays");

	
	MIPData* mipData = (MIPData*)volData;
	unsigned short x_cell_len, y_cell_len, z_cell_len;
	x_cell_len = mipData.x_cell_len;
	y_cell_len = mipData.y_cell_len;
	z_cell_len = mipData.z_cell_len;
	XimgFromX3D = (float*) malloc(sizeof(float) * x_cell_len);
	XimgFromY3D = (float*) malloc(sizeof(float) * y_cell_len);
	XimgFromZ3D = (float*) malloc(sizeof(float) * z_cell_len);
	YimgFromX3D = (float*) malloc(sizeof(float) * x_cell_len);
	YimgFromY3D = (float*) malloc(sizeof(float) * y_cell_len);
	YimgFromZ3D = (float*) malloc(sizeof(float) * z_cell_len);
	
	Point3D* point = [[Point3D alloc] init];
	NSLog(@"\t\tCalculate XimgFromX3D & YimgFromX3D");
	for (unsigned short x = 0; x < x_cell_len; x++)
	{
		[point clear];
		point.x = x;
		point.w = 0.33;
		[point multiple:matFinalProj];
		XimgFromX3D[x] = point.x;
		YimgFromX3D[x] = point.y;
		
#ifdef _TEST_
		printf("(XimgFromX3D, YimgFromX3D) = (%g, %g)\n", XimgFromX3D[x], YimgFromX3D[x]);
#endif
	}
	NSLog(@"\t\tCalculate XimgFromY3D & YimgFromY3D");
	for (unsigned short y = 0; y < y_cell_len; y++)
	{
		[point clear];
		point.y = y;
		point.w = 0.33;
		[point multiple:matFinalProj];
		XimgFromY3D[y] = point.x;
		YimgFromY3D[y] = point.y;
		
		#ifdef _TEST_
		printf("(XimgFromY3D, YimgFromY3D) = (%g, %g)\n", XimgFromY3D[y], YimgFromY3D[y]);
		#endif
	}
	NSLog(@"\t\tCalculate XimgFromZ3D & YimgFromZ3D");
	for (unsigned short z = 0; z < z_cell_len; z++)
	{
		[point clear];
		point.z = z;
		point.w = 0.33;
		[point multiple:matFinalProj];
		XimgFromZ3D[z] = point.x;
		YimgFromZ3D[z] = point.y;
		
		#ifdef _TEST_
		printf("(XimgFromZ3D, YimgFromZ3D) = (%g, %g)\n", XimgFromZ3D[z], YimgFromZ3D[z]);
		#endif
	}
	
	[point release];
	[matFinalProj release];
}

// private - project cell /////////////////
- (void)projectEveryCells
{
	NSLog(@"Begin project every cells");
	
	for (unsigned char i = 0; i < totalBucketCount; i++)
	{
		unsigned int begin = sortedBucketInfo[i].beginIndex;
		unsigned int end = ( i == totalBucketCount-1 ) ? totalCellCount : sortedBucketInfo[i+1].beginIndex;
		unsigned char Cmax = sortedBucketInfo[i].Cmax;
		
		if (Cmax <= levelLowBound)
		{
			break;
		}
		
		for (unsigned int j = begin; j < end; j++)
		{
			unsigned int cellCoord = sortedCellCoord[j];
			unsigned short x, y, z;
			GET_POSION(x, y, z, cellCoord);
			
			[self projectCellWithV1X:x V1Y:y V1Z:z andCmax:Cmax];
		}
	}
	
}
- (void)projectCellWithV1X:(unsigned short)v1x
					   V1Y:(unsigned short)v1y
					   V1Z:(unsigned short)v1z
				   andCmax:(unsigned char)Cmax
{
	float proj_x1_f = XimgFromX3D[v1x] + XimgFromY3D[v1y] + XimgFromZ3D[v1z];
	float proj_y1_f = YimgFromX3D[v1x] + YimgFromY3D[v1y] + YimgFromZ3D[v1z];
	
	short proj_x1_s = (short)floor(proj_x1_f);
	short proj_y1_s = (short)floor(proj_y1_f);
	
	unsigned char subPixelX = (unsigned char) ((proj_x1_f - proj_x1_s) * 4);
	unsigned char subPixelY = (unsigned char) ((proj_y1_f - proj_y1_s) * 4);
	
	// 在proj_x1_f - proj_x1_s非常接近1时，subPixelX计算出来会等于4，y方向的同理
	subPixelX = (subPixelX == 4) ? 3 : subPixelX;
	subPixelY = (subPixelY == 4) ? 3 : subPixelY;
	
	unsigned char templateListIndex = subPixelY * 4 + subPixelX;
	
	Template* template = templates[templateListIndex];
	
	for (; template != NULL; template = template->next)
	{
		short imgX, imgY;
		imgX = proj_x1_s + template->x_offset;
		imgY = proj_y1_s + template->y_offset;
		imgX = (imgX < imageLeft) ? imageLeft : imgX;
		imgY = (imgY < imageTop) ? imageTop : imgY;
		imgX = (imgX > (imageLeft + imageWidth - 1)) ? (imageLeft + imageWidth - 1) : imgX;
		imgY = (imgY > (imageTop + imageHeight - 1)) ? (imageTop + imageHeight - 1) : imgY;
		
		unsigned int imgPos = (imgY-imageTop) * imageWidth + (imgX-imageLeft);
		unsigned char currIntensity = [self intensity:entireImage[imgPos]];
		if (currIntensity >= Cmax)
		{
			continue;
		}
		
		// evaluate ray value;
		RGB rayPoint1Color = [self trillearInterpolationInCell_V1X:v1x V1Y:v1y V1Z:v1z
													  PointWeightU:template->rayX1
																 V:template->rayY1
																 W:template->rayZ1 ];
		
		RGB rayPoint2Color = [self trillearInterpolationInCell_V1X:v1x V1Y:v1y V1Z:v1z
													  PointWeightU:template->rayX2
																 V:template->rayY2
																 W:template->rayZ2 ];
		
		unsigned char rayPoint1Intensity = [self intensity:rayPoint1Color];
		unsigned char rayPoint2Intensity = [self intensity:rayPoint2Color];
		
		unsigned char tmpCmax = MAX2(rayPoint1Intensity, rayPoint2Intensity);
		
		if (currIntensity >= tmpCmax)
		{
			continue;
		}
		
		// 先这么着吧...
		entireImage[imgPos] = (rayPoint1Intensity > rayPoint2Intensity) ? rayPoint1Color : rayPoint2Color;

	}
}

- (RGB)trillearInterpolationInCell_V1X:(unsigned short)v1x
											V1Y:(unsigned short)v1y
											V1Z:(unsigned short)v1z
								   PointWeightU:(float)u
											  V:(float)v
											  W:(float)w
{
	RGB color0, color1, color2, color3, color4, color5, color6, color7;
	BOOL hasSet[8];
	memset(hasSet, 0, sizeof(BOOL) * 8);
	if (u == 0)
	{
		SET_COLOR(color1, 0, 0, 0); hasSet[1] = YES;
		SET_COLOR(color3, 0, 0, 0); hasSet[3] = YES;
		SET_COLOR(color5, 0, 0, 0); hasSet[5] = YES;
		SET_COLOR(color7, 0, 0, 0); hasSet[7] = YES;
	}
	else if (u == 1)
	{
		SET_COLOR(color0, 0, 0, 0); hasSet[0] = YES;
		SET_COLOR(color2, 0, 0, 0); hasSet[2] = YES;
		SET_COLOR(color4, 0, 0, 0); hasSet[4] = YES;
		SET_COLOR(color6, 0, 0, 0); hasSet[6] = YES;
	}
	
	if (v == 0)
	{
		SET_COLOR(color2, 0, 0, 0); hasSet[2] = YES;
		SET_COLOR(color3, 0, 0, 0); hasSet[3] = YES;
		SET_COLOR(color6, 0, 0, 0); hasSet[6] = YES;
		SET_COLOR(color7, 0, 0, 0); hasSet[7] = YES;
	}
	else if (v == 1)
	{
		SET_COLOR(color0, 0, 0, 0); hasSet[0] = YES;
		SET_COLOR(color1, 0, 0, 0); hasSet[1] = YES;
		SET_COLOR(color4, 0, 0, 0); hasSet[4] = YES;
		SET_COLOR(color5, 0, 0, 0); hasSet[5] = YES;
	}
	
	if (w == 0)
	{
		SET_COLOR(color4, 0, 0, 0); hasSet[4] = YES;
		SET_COLOR(color5, 0, 0, 0); hasSet[5] = YES;
		SET_COLOR(color6, 0, 0, 0); hasSet[6] = YES;
		SET_COLOR(color7, 0, 0, 0); hasSet[7] = YES;
	}
	else if(w == 1)
	{
		SET_COLOR(color0, 0, 0, 0); hasSet[0] = YES;
		SET_COLOR(color1, 0, 0, 0); hasSet[1] = YES;
		SET_COLOR(color2, 0, 0, 0); hasSet[2] = YES;
		SET_COLOR(color3, 0, 0, 0); hasSet[3] = YES;
	}
	
	if (!hasSet[0]) color0 = [self getColorAtX:v1x   Y:v1y   Z:v1z];
	if (!hasSet[1]) color1 = [self getColorAtX:v1x+1 Y:v1y   Z:v1z];
	if (!hasSet[2]) color2 = [self getColorAtX:v1x   Y:v1y+1 Z:v1z];
	if (!hasSet[3]) color3 = [self getColorAtX:v1x+1 Y:v1y+1 Z:v1z];
	if (!hasSet[4]) color4 = [self getColorAtX:v1x   Y:v1y   Z:v1z+1];
	if (!hasSet[5]) color5 = [self getColorAtX:v1x+1 Y:v1y   Z:v1z+1];
	if (!hasSet[6]) color6 = [self getColorAtX:v1x   Y:v1y+1 Z:v1z+1];
	if (!hasSet[7]) color7 = [self getColorAtX:v1x+1 Y:v1y+1 Z:v1z+1];
	
	unsigned short c00, c01, c02, c03, c04, c05, c06, c07;
	unsigned short c10, c11, c12, c13;
	unsigned short c20, c21;
	unsigned short r, g, b;
	
	// red /////////////////////////////////////////////
	c00 = color0.r; c01 = color1.r; c02 = color2.r; c03 = color3.r;
	c04 = color4.r; c05 = color5.r; c06 = color6.r; c07 = color7.r;
	
	c10 = c00 * (1-u) + c01 * u;
	c11 = c02 * (1-u) + c03 * u;
	c12 = c04 * (1-u) + c05 * u;
	c13 = c06 * (1-u) + c07 * u;
	
	c20 = c10 * (1-v) + c11 * v;
	c21 = c12 * (1-v) + c13 * v;
	
	r = c20 * (1-w) + c21 * w;
	
	// green //////////////////////////////////////////
	c00 = color0.g; c01 = color1.g; c02 = color2.g; c03 = color3.g;
	c04 = color4.g; c05 = color5.g; c06 = color6.g; c07 = color7.g;
	
	c10 = c00 * (1-u) + c01 * u;
	c11 = c02 * (1-u) + c03 * u;
	c12 = c04 * (1-u) + c05 * u;
	c13 = c06 * (1-u) + c07 * u;
	
	c20 = c10 * (1-v) + c11 * v;
	c21 = c12 * (1-v) + c13 * v;
	
	g = c20 * (1-w) + c21 * w;
	
	// blue ///////////////////////////////////////////
	c00 = color0.b; c01 = color1.b; c02 = color2.b; c03 = color3.b;
	c04 = color4.b; c05 = color5.b; c06 = color6.b; c07 = color7.b;
	
	c10 = c00 * (1-u) + c01 * u;
	c11 = c02 * (1-u) + c03 * u;
	c12 = c04 * (1-u) + c05 * u;
	c13 = c06 * (1-u) + c07 * u;
	
	c20 = c10 * (1-v) + c11 * v;
	c21 = c12 * (1-v) + c13 * v;
	
	b = c20 * (1-w) + c21 * w;
	
	
	RGB color;
	SET_COLOR(color, r, g, b);
	return color;
}

// other ///////////////////////////////////////
- (void)clean
{
	if (sortedBucketInfo)
	{
		sortedBucketInfo = NULL;
	}
	if (sortedCellCoord)
	{
		sortedCellCoord = NULL;
	}

	if (XimgFromX3D)
	{
		free(XimgFromX3D);
		XimgFromX3D = NULL;
	}
	if (XimgFromY3D)
	{
		free(XimgFromY3D);
		XimgFromY3D = NULL;
	}
	if (XimgFromZ3D)
	{
		free(XimgFromZ3D);
		XimgFromZ3D = NULL;
	}
	if (YimgFromX3D)
	{
		free(YimgFromX3D);
		YimgFromX3D = NULL;
	}
	if (YimgFromY3D)
	{
		free(YimgFromY3D);
		YimgFromY3D = NULL;
	}
	if (YimgFromZ3D)
	{
		free(YimgFromZ3D);
		YimgFromZ3D = NULL;
	}
	
	for (char i = 0; i < 16; i++)
	{
		if (templates[i])
		{
			[self delTemplateList:i];
			templates[i] = NULL;
		}
	}
	
}

- (void)addTemplate:(Template*)template toList:(char)listIndex // 添加一个模版到链表表首
{
	if (templates[listIndex] == NULL)
	{
		templates[listIndex] = template;
	}
	else
	{
		template->next = templates[listIndex];
		templates[listIndex] = template;
	}

}

- (Template*)findTemplateFromList:(char)listIndex WithX:(short)x Y:(short)y
{
	Template* p = templates[listIndex];
	while (p != NULL)
	{
		if (p->x_offset == x && p->y_offset == y)
		{
			return p;
		}
		p = p->next;
	}
	
	return NULL;
}

- (void)delTemplateList:(char)listIndex  // 删除一条链表
{
	Template *p1, *p2;
	p1 = templates[listIndex];
	while (p1 != NULL)
	{
		p2 = p1->next;
		free(p1);
		p1 = p2;
	}
}

- (unsigned char)intensity:(RGB)color
{
	if (channelCount == 1)
	{
		return (unsigned char) color.r;
	}
	
	// channelCount == 3
	unsigned short i = 0;
	unsigned char c = 0;
	MIPData* mipData = (MIPData*)volData;
	if (mipData.isRedDisplay)
	{
		i += (unsigned short) color.r;
		c++;
	}
	if (mipData.isGreenDisplay)
	{
		i += (unsigned short) color.g;
		c++;
	}
	if (mipData.isBlueDisplay)
	{
		i += (unsigned short) color.b;
		c++;
	}
	if (c == 0)
	{
		return 0;
	}
	else
	{
		return i / c;
	}
}

- (RGB)getColorAtX:(unsigned short)x Y:(unsigned short)y Z:(unsigned short)z
{
	RGB color;
	
#ifndef _TEST_
	unsigned char r = 0, g = 0, b = 0;
	if (channelCount == 1)
	{
		r = g = b = rawData[0][z][y][x];
	}
	else // channelCount == 3
	{
		MIPData* mipData = (MIPData*)volData;
		if (mipData.isRedDisplay)
		{
			r = rawData[0][z][y][x];
		}
		if (mipData.isGreenDisplay)
		{
			g = rawData[1][z][y][x];
		}
		if (mipData.isBlueDisplay)
		{
			b = rawData[2][z][y][x];
		}
	}
	SET_COLOR(color, r, g, b);
	
	return color;
	
#else
	
	MIPData* mipData = (MIPData*)volData;
	unsigned char* testData = mipData.testData;
	unsigned short index = z * mipData.x_len * mipData.y_len + y * mipData.x_len + x;
	SET_COLOR(color, testData[index], 0, 0);
	return color;
	
#endif

}

- (RGB)colorAverageWithColor1:(RGB)color1 Color2:(RGB)color2
{
	unsigned short r1, r2, g1, g2, b1, b2;
	r1 = color1.r;
	g1 = color1.g;
	b1 = color1.b;
	r2 = color2.r;
	g2 = color2.g;
	b2 = color2.b;
	
	r1 = (r1 + r2) >> 1;
	g1 = (g1 + g2) >> 1;
	b1 = (b1 + b2) >> 1;
	
	RGB color;
	SET_COLOR(color, r1, g1, b1);
	return color;
}

- (void)remapColor:(RGB*)color
{
	float diff = levelUpBound - levelLowBound;
	if (diff <= 0)
	{
		return;
	}
	
	// red //
	if (color->r <= levelLowBound)
	{
		color->r = 0;
	}
	else if (color->r >= levelUpBound)
	{
		color->r = 255;
	}
	else
	{
		color->r = (color->r - levelLowBound) / diff * 255.0;
	}
	
	// green //
	if (color->g <= levelLowBound)
	{
		color->g = 0;
	}
	else if (color->g >= levelUpBound)
	{
		color->g = 255;
	}
	else
	{
		color->g = (color->g - levelLowBound) / diff * 255.0;
	}
	
	// blue //
	if (color->b <= levelLowBound)
	{
		color->b = 0;
	}
	else if (color->b >= levelUpBound)
	{
		color->b = 255;
	}
	else
	{
		color->b = (color->b - levelLowBound) / diff * 255.0;
	}

}
@end
